package main.java;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Scanner;
import java.util.Set;

import javax.xml.XMLConstants;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.*;

import model.entities.MeasureUnit;
import model.entities.UserCode;

import org.apache.log4j.Logger;
import org.xml.sax.SAXException;

public class GSI2LandXML
{
	private DAO dao = new DAO();

	private Date creationTime;
	private String measurementTime;
	private CgPoint refCgPoint;
	private ArrayList<CgPoint> cgPoints = new ArrayList<CgPoint>();
	private ArrayList<RawObservation> rawObservations = new ArrayList<RawObservation>();

	private HashMap<String,String> codeBlocks = new HashMap<String,String>();

	// Counter for successful/failed data words interpretations
	private long successCounter = 0;
	private long failedCounter = 0;
	private ArrayList<String> failedBlocks = new ArrayList<String>();
	private ArrayList<String> failedDatawords = new ArrayList<String>();

	// Number of data words
	private long totalNumberOfDatawords = 0;

	private String printPath = "";
	private String printName = "";
	private final String FILE_SEPARATOR = "-----------------------------------";

	private String xmlOutputPath = "";

	private static final String XMLNS = "http://www.landxml.org/schema/LandXML-1.2";
	private static final String XMLNS_XSI = "http://www.w3.org/2001/XMLSchema-instance";
	private static final String XSI_SCHEMA_LOCATION = "http://www.landxml.org/schema/LandXML-1.2 http://www.landxml.org/schema/LandXML-1.2/LandXML-1.2.xsd";

	private static final String LAND_XML_XSD_SCHEMA_LOCATION = "http://www.landxml.org/schema/LandXML-1.2/LandXML-1.2.xsd";

	private static Logger logger = Logger.getLogger(GSI2LandXML.class);

	public GSI2LandXML()
	{
	}

	public String convertGSI2LandXML(ArrayList<String> gsiFiles) throws IOException
	{
		String gsiContent = "";
		boolean validGSI = false;

		for(String gsiFile : gsiFiles)
		{
			int separatorIndex = gsiFile.lastIndexOf("/");
			if(separatorIndex == -1)
			{
				separatorIndex = gsiFile.lastIndexOf("\\");
			}
			String fPath = gsiFile.substring(0, separatorIndex + 1);
			String fName = gsiFile.substring(separatorIndex + 1);

			if(printPath.equals("")) printPath = fPath;
			if(printName.equals("")) printName = fName;

			String content = readDocument(fPath, fName);
			validGSI = validateGSIContent(content);
			if(!validGSI)
			{
				break;
			}

			totalNumberOfDatawords += getNumberOfDatawordsFromContent(content);

			gsiContent += content;
			gsiContent += "\n" + FILE_SEPARATOR + "\n";
		}

		System.out.println("------------------------------ GSI content - Start: ------------------------------");
		System.out.println(gsiContent);
		System.out.println("------------------------------ GSI content - End: ------------------------------");

		if(validGSI)
		{
			Scanner reader = new Scanner(gsiContent);
			String block = "";
			String dataword = "";
			String firstWI = "";

			// Temporary variables
			RawObservation ro = null;
			CgPoint cgp = null;

			boolean datawordValid = false;

			// Reading each block
			while(reader.hasNextLine())
			{
				block = reader.nextLine();

				if(block.startsWith("*"))
				{
					firstWI = block.substring(1, 3);

					System.out.println("First dataword: " + block.substring(1, 24));
					if(block.length() > 24) {
						System.out.println("Rest block: " + block.substring(25));
					}

					if(firstWI.equals("11"))
					{
						Scanner blockReader = new Scanner(block.substring(1, block.length()));

						while(blockReader.hasNext())
						{
							dataword = blockReader.next();

							// Scanner's next-method just goes to next whitespace
							// Following loop is needed to get complete data word
							while (dataword.length() < 23) {
								dataword += " " + blockReader.next();
							}
							System.out.println("Dataword is: " + dataword);

							// If RawObservation or CgPoint with same name already exists take the existing one
							// otherwise generate new object
							boolean roExist = false;
							boolean cgpExist = false;

							if(dataword.startsWith("11"))
							{
								String value = "";

								// Get value from data word
								for(int i = 7; i < dataword.length(); i++) {
									if(dataword.charAt(i) != '0') {
										value = dataword.substring(i, dataword.length());
										break;
									}
								}
								if(value.equals("")) value = "0";

								System.out.println("Value of dataword is: " + value);

								for (int i = 0; i < rawObservations.size(); i++)
								{
									if (rawObservations.get(i).getName().equals(value))
									{
										ro = rawObservations.get(i);
										roExist = true;
										break;
									}
								}
								for (int i = 0; i < cgPoints.size(); i++)
								{
									if (cgPoints.get(i).getName().equals(value))
									{
										cgp = cgPoints.get(i);
										cgpExist = true;
										break;
									}
								}
								if(!roExist)
								{
									ro = new RawObservation();
									ro.setName(value);
									rawObservations.add(ro);
								}
								if(!cgpExist)
								{
									cgp = new CgPoint();
									cgp.setName(value);
									cgPoints.add(cgp);
								}
								if(!this.codeBlocks.isEmpty()) {
									// Set values of previous 41 code blocks in RawObservation and CgPoint
									this.convertCodeBlocksDB(ro, cgp);
								}
								successCounter++;
							}
							else
							{
								// Add information to target objects from other data words of the 11 block
								datawordValid = addInformation(dataword, ro, cgp);
								if (!datawordValid) {
									failedDatawords.add(dataword);
									failedCounter++;
								} else {
									successCounter++;
								}
							}
						}

						blockReader.close();
					}
					else if(firstWI.equals("41"))
					{
						String firstCB = block.substring(1, 24);
						String userCode = "";

						for(int i = 7; i < firstCB.length(); i++) {
							if(firstCB.charAt(i) != '0') {
								userCode = firstCB.substring(i, firstCB.length());
								break;
							}
						}

						System.out.println("Usercode is: " + userCode);

						if (userCode.equals("DATUM"))
						{
							this.codeBlocks.put(userCode, block.substring(25));
							successCounter += getNumberOfDatawordsFromBlock(block.substring(25));
							successCounter++;
						}
						else
						{
							try
							{
								// Check if user code is known in DB, if not don't save
								List<UserCode> ucsDB = dao.getUserCodesByCode(userCode);
								if(ucsDB.size() > 0) {
									this.codeBlocks.put(Integer.parseInt(userCode) + "", block.substring(25));
									successCounter += getNumberOfDatawordsFromBlock(block.substring(25));
									successCounter++;
								} else {
									failedBlocks.add(block);
									failedCounter += getNumberOfDatawordsFromBlock(block);
								}
							}
							catch (NumberFormatException ne)
							{
								failedBlocks.add(block);
								failedCounter += getNumberOfDatawordsFromBlock(block);
							}
						}
					}
				}
				else if(block.equals(FILE_SEPARATOR))
				{
					this.codeBlocks.clear();
				}
				else
				{
					logger.debug("INVALID BLOCK. Block doesn't start with * character.");
				}
			}

			reader.close();

			// Generate LandXML document
			String output = generateXMLContent();
			printDocument(printPath, printName, ".xml", output);

			// Generate failed interpretations document
			String failedIntPret = getFailedIntPretContent();
			printDocument(printPath, printName + "_report", ".txt", failedIntPret);

			return output;
		}
		else
		{
			return "GSI CONVERSION FAILED. GSI content is not valid.";
		}
	}

	/**
	 * @param dataword
	 * @param ro
	 * @param cgp
	 * @return
	 */
	private boolean addInformation(String dataword, RawObservation ro, CgPoint cgp)
	{
		try
		{
			// Splitting data word
			int wi = Integer.parseInt(dataword.substring(0, 2));
			String measure = "" + dataword.charAt(5);
			String sign = "" + dataword.charAt(6);
			String value = "";

			// Get value from data word
			for(int i = 7; i < dataword.length(); i++) {
				if(dataword.charAt(i) != '0') {
					value = dataword.substring(i, dataword.length());
					break;
				}
			}
			if(value.equals("")) value = "0";

			System.out.println("Value ist: " + value);

			int mUnit;
			double dValue;

			switch(wi) {
			case 21:
				mUnit = Integer.parseInt(measure);

				dValue = Double.parseDouble(value);
				if(sign.equals("-")) { dValue *= -1; }

				ro.setHorizAngle(convertValue(mUnit, dValue));
				break;
			case 22:
				mUnit = Integer.parseInt(measure);

				dValue = Double.parseDouble(value);
				if(sign.equals("-")) { dValue *= -1; }

				ro.setZenithAngle(convertValue(mUnit, dValue));
				break;
			case 31:
				mUnit = Integer.parseInt(measure);

				dValue = Double.parseDouble(value);
				if(sign.equals("-")) { dValue *= -1; }

				ro.setSlopeDistance(convertValue(mUnit, dValue));

				break;
			case 47:
				if (value.equals("Reflectorless")) {
					ro.addProperty("EDMType", "reflectorLess");
					ro.addProperty("reflectorName", "");
				} else {
					ro.addProperty("EDMType", "reflector");
					ro.addProperty("reflectorName", value);
				}
				break;
			case 58:
				if (value.equals("0")) {
					ro.addProperty("reflectorConstant", "0.000000");
				} else {
					mUnit = Integer.parseInt(measure);

					dValue = Double.parseDouble(value);
					if(sign.equals("-")) { dValue *= -1; }

					ro.addProperty("reflectorConstant", formatDoubleValue(convertValue(mUnit, dValue), 6));
				}
				break;
			case 81 :
				mUnit = Integer.parseInt(measure);

				dValue = Double.parseDouble(value);
				if(sign.equals("-")) { dValue *= -1; }

				ro.setXValue(convertValue(mUnit, dValue));
				cgp.setXValue(convertValue(mUnit, dValue));
				break;
			case 82 :
				mUnit = Integer.parseInt(measure);

				dValue = Double.parseDouble(value);
				if(sign.equals("-")) { dValue *= -1; }

				ro.setYValue(convertValue(mUnit, dValue));
				cgp.setYValue(convertValue(mUnit, dValue));
				break;
			case 83 :
				mUnit = Integer.parseInt(measure);

				dValue = Double.parseDouble(value);
				if(sign.equals("-")) { dValue *= -1; }

				ro.setZValue(convertValue(mUnit, dValue));
				cgp.setZValue(convertValue(mUnit, dValue));
				break;
			default:
				return false;
			}
		}
		catch (NumberFormatException ne)
		{
			return false;
		}

		return true;
	}

	private void convertCodeBlocksDB(RawObservation ro, CgPoint cgp)
	{
		String dataword = "";

		// Split data word
		String wi = "";
		String sign = "";
		String value = "";

		double dValue = 0.0;

		Set<String> userCodes = codeBlocks.keySet();
		for(String userCode : userCodes)
		{
			// Scans the rest block of the code block with user code 'userCode'
			Scanner reader = new Scanner(codeBlocks.get(userCode));

			// Special case: user code DATUM
			if (userCode.equals("DATUM")) {
				dataword = reader.next();

				// Scanner's next-method just goes to next whitespace
				// Following loop is needed to get complete data word
				while (dataword.length() < 23) {
					dataword += " " + reader.next();
				}
				System.out.println("41er-Block Datum Datenwort ist: " + dataword);

				// Get value from data word
				wi = dataword.substring(0, 2);
				for (int i = 7; i < dataword.length(); i++) {
					if (dataword.charAt(i) != '0') {
						value = dataword.substring(i, dataword.length());
						break;
					}
				}

				measurementTime = value.replace(' ', 'T');
				measurementTime += ":00";
				ro.setTimeStamp(measurementTime);
				cgp.setTimeStamp(measurementTime);
			} else {
				while (reader.hasNext()) {
					dataword = reader.next();

					// Scanner's next-method just goes to next whitespace
					// Following loop is needed to get complete data word
					while (dataword.length() < 23) {
						dataword += " " + reader.next();
					}

					wi = dataword.substring(0, 2);
					sign = "" + dataword.charAt(6);
					for (int i = 7; i < dataword.length(); i++) {
						if (dataword.charAt(i) != '0') {
							value = dataword.substring(i, dataword.length());
							break;
						}
					}

					// Get user code entries from DB
					List<UserCode> userCodesDB = dao.getUserCodesByCode(userCode);
					UserCode uc = null;
					for (UserCode userCodeDB : userCodesDB) {
						if (wi.equals("" + userCodeDB.getWi())) {
							uc = userCodeDB;
							break;
						}
					}

					// User code DB entry with given Code and given WI exists
					if (uc != null) {
						// Special case: user code 11
						if (uc.getCode() == 11) {
							if(refCgPoint == null) {
								refCgPoint = new CgPoint();
								refCgPoint.setMeasured(false);
								cgPoints.add(0, refCgPoint);
							}
							cgp.addProperty("code", "11");
							if (uc.getWi() == 42) {
								if(refCgPoint != null) {
									refCgPoint.setName(value);
								}
							} else if (uc.getWi() == 43) {
								if(refCgPoint != null) {
									dValue = Double.parseDouble(value);
									if(sign.equals("-")) { dValue *= -1; }
									refCgPoint.setInstrumentHeight(dValue);
								}
							}
						}

						// For double value
						if (value.matches("\\d+.?\\d*")) {
							dValue = Double.parseDouble(value);
							if(sign.equals("-")) { dValue *= -1; }
							value = "" + dValue;
						}

						// Target
						if (uc.getTarget().equals("CGP")) {
							cgp.addProperty(uc.getLabel(), value);
						} else if (uc.getTarget().equals("RO")) {
							ro.addProperty(uc.getLabel(), value);
						} else if (uc.getTarget().equals("CGP-RO")) {
							cgp.addProperty(uc.getLabel(), value);
							ro.addProperty(uc.getLabel(), value);
						}
					} else {
						// User code DB entry exists with given Code but not with given WI
						failedDatawords.add(dataword);

						// Delete data word from block
						Scanner oldCodeBlock = new Scanner(codeBlocks.get(userCode));
						String oldDataword = "";

						String newCodeBlock = "";
						while(oldCodeBlock.hasNext()) {
							oldDataword = oldCodeBlock.next();
							while(oldDataword.length() < 23) {
								oldDataword += " " + oldCodeBlock.next();
							}
							if(!oldDataword.equals(dataword)) {
								newCodeBlock += oldDataword + " ";
							}
						}

						oldCodeBlock.close();
						codeBlocks.put(userCode, newCodeBlock.trim());

						// Success counter minus 1 because data word was set as successful first
						successCounter--;
						failedCounter++;
					}
				}
			}

			reader.close();
		}
	}

	private double convertValue(int measure, double value)
	{
		MeasureUnit mu = dao.getMeasureUnitById(new Long(measure));
		return value * mu.getConversion();
	}

	private String readDocument(String fPath, String fName) throws IOException
	{
		StringBuilder text = new StringBuilder();
		String lineSeparator = System.getProperty("line.separator");
		Scanner scanner = new Scanner(new FileInputStream(fPath + fName));
		try
		{
			while (scanner.hasNextLine())
			{
				text.append(scanner.nextLine() + lineSeparator);
			}
		}
		finally
		{
			scanner.close();
		}

		String fileContent = text.toString();
		return fileContent;
	}

	private void printDocument(String fPath, String fName, String fExt, String fContent) throws IOException
	{
		Date now = new Date();
		SimpleDateFormat timeFormatter = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss");
		String time = timeFormatter.format(now);

		if(fExt.equals(".xml"))
		{
			xmlOutputPath = fPath + fName + "_(" + time + ")" + fExt;
		}
		Writer out = new OutputStreamWriter(new FileOutputStream(fPath + fName + "_(" + time + ")" + fExt));

		try
		{
			out.write(fContent);
		}
		finally
		{
			out.close();
		}
	}

	public String getXmlOutputPath() {
		return xmlOutputPath;
	}

	public boolean validateGSIContent(String gsiContent)
	{
		boolean valid = gsiContent.matches("(\\*.{23}(\\s.{23})*(\\s)*(\\n)?|(\\n)?)*");
		System.out.println("GSI content is valid: " + valid);
		return valid;
	}

	public boolean validateLandXML(File xmlFile) throws MalformedURLException, SAXException, IOException {
		SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

		URL schemaLocation = new URL(LAND_XML_XSD_SCHEMA_LOCATION);
		Schema schema = factory.newSchema(schemaLocation);

		Validator validator = schema.newValidator();

		Source xmlFileSource = new StreamSource(xmlFile);

		try {
			validator.validate(xmlFileSource);
			logger.debug(xmlFile.getName() + " is VALID");
			return true;
		} catch (SAXException ex) {
			logger.debug(xmlFile.getName() + " is NOT VALID because ");
			logger.debug(ex.getMessage());
		}

		return false;
	}

	public long getSuccessCounter() {
		return successCounter;
	}

	public long getFailedCounter() {
		return failedCounter;
	}

	public long getTotalNumberOfDatawords() {
		return totalNumberOfDatawords;
	}

	private String getFailedIntPretContent()
	{
		String failedIntPret = "GSI to LandXML conversion report\n"
				+ "Created at: " + getDateString(creationTime) + " " + getTimeString(creationTime) + "\n\n"
				+ "Total number of data words to interpret: " + totalNumberOfDatawords + "\n\n"
				+ "Number of successful data words interpretations: " + successCounter + "\n"
				+ "Number of failed data words interpretations: " + failedCounter + "\n\n";
		failedIntPret += getFailedBlocks() + "\n";
		failedIntPret += getFailedDatawords();

		return failedIntPret;
	}

	public String getFailedBlocks() {
		String failed = "Blocks failed to interpret:\n\n";
		for(String fB : failedBlocks)
		{
			failed += fB + "\n";
		}
		return failed;
	}

	public String getFailedDatawords() {
		String failed = "Data words failed to interpret:\n\n";
		for(String fB : failedDatawords)
		{
			failed += fB + "\n";
		}
		return failed;
	}

	private String generateXMLContent()
	{
		this.creationTime = new Date();

		String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
				+ "<LandXML xmlns=\"" + XMLNS + "\" xmlns:xsi=\"" + XMLNS_XSI + "\" "
				+ "xsi:schemaLocation=\"" + XSI_SCHEMA_LOCATION + "\" "
				+ "version=\"1.2\" date=\"" + getDateString(this.creationTime) + "\" time=\"" + getTimeString(this.creationTime) + "\" readOnly=\"false\" language=\"English\">\n"
				+ getUnitsInfo() + "\n"
				+ getCoordinateSystemInfo() + "\n"
				+ getProvenienceInfo() + "\n"
				+ getCgPoints() + "\n"
				+ "<Survey>\n"
				+ "<SurveyHeader name=\"\"/>\n"
				+ getEquipmentInfo() + "\n"
				+ getInstrumentSetupInfo() + "\n"
				+ "</Survey>\n"
				+ "</LandXML>";

		return xml;
	}

	private String getUnitsInfo()
	{
		String unitsInfo = "<Units>\n"
				+ "<Metric linearUnit=\"meter\" areaUnit=\"squareMeter\" volumeUnit=\"cubicMeter\" angularUnit=\"decimal degrees\" "
				+ "latLongAngularUnit=\"decimal degrees\" temperatureUnit=\"celsius\" pressureUnit=\"milliBars\"/>\n"
				+ "</Units>";

		return unitsInfo;
	}

	private String getCoordinateSystemInfo()
	{
		String csInfo = "<CoordinateSystem name=\"DP\" horizontalDatum=\"Local\" verticalDatum=\"Local\" ellipsoidName=\"Bessel\" fileLocation=\"\">\n"
				+ "<Feature code=\"ellipsoid\">\n"
				+ "<Property label=\"name\" value=\"Bessel\"/>\n"
				+ "<Property label=\"semiMajorAxis\" value=\"" + "6378137.000000000000000" + "\"/>\n"
				+ "<Property label=\"1/flattening\" value=\"" + "298.257223563000030" + "\"/>\n"
				+ "</Feature>\n"
				+ "</CoordinateSystem>";

		return csInfo;
	}

	private String getProvenienceInfo()
	{
		String ts = getDateString(this.creationTime) + "T" + getTimeString(this.creationTime);
		String provenienceInfo = "<Application name=\"LandXML Export\" manufacturer=\"Data set migration group 2\" version=\"1.0\" manufacturerURL=\"www.dpue-group-2.com\">\n"
				+ "<Author company=\"Data set migration group 2\" companyURL=\"www.dpue-group-2.com\" timeStamp=\"" + ts + "\"/>\n"
				+ "</Application>";

		return provenienceInfo;
	}

	private String getCgPoints()
	{
		if(refCgPoint != null)
		{
			refCgPoint.setTimeStamp(measurementTime);
		}

		String cgps = "";
		int counter = 0;
		for(CgPoint cgp : cgPoints)
		{
			cgps += cgp.getCgPoint();
			if(counter < (cgPoints.size() - 1)) cgps += "\n";
			counter++;
		}
		return cgps;
	}

	private String getEquipmentInfo()
	{
		String instrumentDetails = "<Equipment>\n"
				+ "<InstrumentDetails id=\"TPS_3\" manufacturer=\"Leica Geosystems AG\" model=\"TCRP120x\" serialNumber=\"123456\" "
				+ "horizCollimation=\"0.000000000000\" vertCollimation=\"0.000000000000\">\n"
				+ "<Corrections>\n"
				+ "<Feature code=\"TPSCorrection\">\n"
				+ "<Property label=\"oID\" value=\"6\"/>\n"
				+ "<Property label=\"referenceRadius\" value=\"6371400.000000\"/>\n"
				+ "<Property label=\"offsetCentralMeridian\" value=\"0.000000\"/>\n"
				+ "<Property label=\"scaleFactorCentralMeridian\" value=\"1.000000\"/>\n"
				+ "<Property label=\"dryTemperature\" value=\"12.000000\"/>\n"
				+ "<Property label=\"wetTemperature\" value=\"8.264283\"/>\n"
				+ "<Property label=\"pressure\" value=\"1013.250000\"/>\n"
				+ "<Property label=\"refractionCoefficient\" value=\"0.130000\"/>\n"
				+ "<Property label=\"atmosphericPPM\" value=\"0.000000\"/>\n"
				+ "<Property label=\"projectionPPM\" value=\"0.000000\"/>\n"
				+ "<Property label=\"heightReductionPPM\" value=\"0.000000\"/>\n"
				+ "<Property label=\"individualPPM\" value=\"0.000000\"/>\n"
				+ "</Feature>\n"
				+ "</Corrections>\n"
				+ "</InstrumentDetails>\n"
				+ "</Equipment>";

		return instrumentDetails;
	}

	private String getInstrumentSetupInfo()
	{
		String refName = "unknown";
		double refHeight = 0;
		double refXValue = 0;
		double refYValue = 0;
		double refZValue = 0;

		if(refCgPoint != null)
		{
			refName = refCgPoint.getName();
			refHeight = refCgPoint.getInstrumentHeight();
			refXValue = refCgPoint.getXValue();
			refYValue = refCgPoint.getYValue();
			refZValue = refCgPoint.getZValue();
		}

		String iSInfo = "<InstrumentSetup id=\"TPSSetupID_23\" instrumentDetailsID=\"TPS_3\" stationName=\""
				+ refName + "\" instrumentHeight=\"" + refHeight + "\" "
				+ "orientationAzimuth=\"0.000000000000\">\n"
				+ "<Feature code=\"TPSSetup\">\n"
				+ "<Property label=\"type\" value=\"unknown\"/>\n"
				+ "</Feature>\n"
				+ "<InstrumentPoint pntRef=\"" + refName + "\" timeStamp=\"" + measurementTime + "\">"
				+ formatDoubleValue(refXValue, 6) + " " + formatDoubleValue(refYValue, 6) + " "
				+ formatDoubleValue(refZValue, 6) + "</InstrumentPoint>\n"
				+ getRawObservations() + "\n"
				+ "</InstrumentSetup>";

		return iSInfo;
	}

	private String getRawObservations()
	{
		String ros = "";
		int counter = 0;
		for(RawObservation ro : rawObservations)
		{
			ros += ro.getRawObservation();
			if(counter < (rawObservations.size() - 1)) ros += "\n";
			counter++;
		}
		return ros;
	}

	private String getDateString(Date d)
	{
		SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd");
		return date.format(d);
	}

	private String getTimeString(Date d)
	{
		SimpleDateFormat time = new SimpleDateFormat("HH:mm:ss");
		return time.format(d);
	}

	private String formatDoubleValue(double value, int decimals)
	{
		DecimalFormatSymbols otherSeperators = new DecimalFormatSymbols(Locale.GERMAN);
		otherSeperators.setDecimalSeparator('.');
		otherSeperators.setGroupingSeparator(','); 
		DecimalFormat df = new DecimalFormat("0.0", otherSeperators);
		df.setMinimumFractionDigits(decimals);
		df.setMaximumFractionDigits(decimals);

		return df.format(value);
	}

	private int getNumberOfDatawordsFromContent(String content)
	{
		Scanner reader = new Scanner(content);
		String block = "";
		String dataword = "";
		int counter = 0;
		while(reader.hasNextLine())
		{
			block = reader.nextLine();
			if(block.length() > 0)
			{
				Scanner blockReader = new Scanner(block.substring(1));
				while(blockReader.hasNext())
				{
					dataword = blockReader.next();
					while(dataword.length() < 23) {
						dataword += " " + blockReader.next();
					}
					counter++;
				}
				blockReader.close();
			}
		}
		reader.close();
		return counter;
	}

	private int getNumberOfDatawordsFromBlock(String block)
	{
		Scanner reader = new Scanner(block);
		String dataword = "";
		int counter = 0;
		while(reader.hasNext())
		{
			dataword = reader.next();
			while(dataword.length() < 23) {
				dataword += " " + reader.next();
			}
			counter++;
		}
		reader.close();
		return counter;
	}
}